import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.JPanel;


//This is a rotated square (diamond) that splits a given number of times until the maxdepth is reached
public class RotSquare{

	//Points describe containing square
	Point upperLeft;
	Point lowerRight;
	RotSquare children[]; //if it is null then it has not been split
	JPanel lJP;
	int[][] rgbArray;
	
	public static RotSquare newRotSquareTouching;
	public static boolean quickReveal = false;

	//Pass in the containing square points
	public RotSquare(Point upperLeft, Point lowerRight, int[][] rgbArray, JPanel lJP){
		this.upperLeft = upperLeft;
		this.lowerRight = lowerRight;
		this.lJP = lJP;
		this.rgbArray = rgbArray;
	}

	public void splitRotSquare(MouseEvent e){
		if (isSplitable())
			createChildren(e);
		else if (children != null){
			for (RotSquare child : children)
				if (child.hasMousePointer(e))
					child.splitRotSquare(e);
		}
		lJP.repaint();
	}
	private void createChildren(MouseEvent e){
		children = new RotSquare[NUMBER_OF_CHILDREN];
		int rs_width = lowerRight.x - upperLeft.x;
		int rs_height = lowerRight.y - upperLeft.y;
		for (int i = 0; i < NUMBER_OF_CHILDREN; i++){
			children[i] = new RotSquare(new Point(upperLeft.x + (i % 2) * rs_width / 2, upperLeft.y + (i / 2) * rs_height / 2),
					new Point(lowerRight.x - ((i + 1) % 2) * rs_width / 2, lowerRight.y - ((NUMBER_OF_CHILDREN - i - 1) / 2) * rs_height / 2),
					getQuarterArray(i), lJP);
			if (children[i].hasMousePointer(e))
				newRotSquareTouching = children[i];
		}
		rgbArray = null; //to allow garbage clean up since we don't need this array anymore
	}
	private int[][] getQuarterArray (int number) {
		// [ 0 1 ]
		// [ 2 3 ]
		int width = (lowerRight.x - upperLeft.x) / 2;
		int height = (lowerRight.y - upperLeft.y) / 2;
		int startX = (number % 2) * width;
		int startY = (number / 2) * height;
		int[][] retArray = new int[width][height];
		for (int i = startX; i < startX + width; i++)
			for (int j = startY; j < startY + height; j++)
				retArray[i-startX][j-startY] = rgbArray[i][j];
		return retArray;
	}
	public void drawRotSquare(Graphics g){
		//if rotsquare is visible draw it, otherwise tell its children to draw themselves
		if(children == null){
			
			//RotSquare
			int[] xCords = new int[]{lowerRight.x, upperLeft.x + (lowerRight.x - upperLeft.x) / 2, upperLeft.x, upperLeft.x + (lowerRight.x - upperLeft.x) / 2};
			int[] yCords = new int[]{upperLeft.y + (lowerRight.y - upperLeft.y) / 2, upperLeft.y, upperLeft.y + (lowerRight.y - upperLeft.y) / 2, lowerRight.y};
			
			//Square
			//int[] xCords = new int[]{lowerRight.x, upperLeft.x, upperLeft.x, lowerRight.x};
			//int[] yCords = new int[]{upperLeft.y, upperLeft.y, lowerRight.y, lowerRight.y};
			
			//Octagon
			/*int width = (lowerRight.x - upperLeft.x);
			int height = (lowerRight.y - upperLeft.y);
			int[] xCords = new int[]{lowerRight.x, lowerRight.x - width / 3, upperLeft.x + width / 3, upperLeft.x,
					upperLeft.x, upperLeft.x + width / 3, lowerRight.x - width / 3, lowerRight.x};
			int[] yCords = new int[]{upperLeft.y + height / 3, upperLeft.y, upperLeft.y, upperLeft.y + height / 3,
					lowerRight.y - height / 3, lowerRight.y, lowerRight.y, lowerRight.y - height / 3};
			*/
			g.setColor(getRSColor());
			g.fillPolygon(xCords, yCords, xCords.length);
		}
		else {
			for (RotSquare child : children){
				child.drawRotSquare(g);
			}
		}
	}
	
	private Color getRSColor(){
		long r = 0, g = 0, b = 0;
		for (int i = 0; i < rgbArray.length; i++)
			for (int j = 0; j < rgbArray[i].length; j++){
				r += rgbArray[i][j] & 0xFF;
				g += (rgbArray[i][j] >> 8) & 0xFF;
				b += (rgbArray[i][j] >> 16) & 0xFF;
			}
		r /= rgbArray.length * rgbArray[0].length;
		g /= rgbArray.length * rgbArray[0].length;
		b /= rgbArray.length * rgbArray[0].length;
		return new Color((int) b, (int) g, (int) r);
	}
	
	
	private boolean isSplitable(){
		int rs_width = lowerRight.x - upperLeft.x;
		int rs_height = lowerRight.y - upperLeft.y;
		boolean touched = newRotSquareTouching == null || newRotSquareTouching != this;
		return children == null && touched && rs_width / 2 >= MIN_ROTSQUARE_WIDTH && rs_height / 2 >= MIN_ROTSQUARE_HEIGHT;
	}
	public boolean hasMousePointer(MouseEvent e) {
		boolean satisfiesX = e.getX() >= upperLeft.x && e.getX() <= lowerRight.x;
		boolean satisfiesY = e.getY() >= upperLeft.y && e.getY() <= lowerRight.y;
		if (quickReveal)
			return true;
		return satisfiesX && satisfiesY;
	}
	
	private static final int MIN_ROTSQUARE_WIDTH = 1;
	private static final int MIN_ROTSQUARE_HEIGHT = 1;
	private static final int NUMBER_OF_CHILDREN = 4;
}
